﻿using System;
using System.Collections.Generic;
using System.Reflection;

namespace ArgusLight.Reflection
{
	public static class AssemblyReflector
	{
		/// <summary>
		/// Returns all <see cref="Type"/>s in all the assemblies of the current <see cref="AppDomain"/>.
		/// </summary>
		/// <returns>Type[]</returns>
		public static Type[] GetTypes()
		{
			Assembly[] asm = AppDomain.CurrentDomain.GetAssemblies();
			List<Type> RetVal = new List<Type>();
			foreach (Assembly a in asm)
			{
				try
				{
					RetVal.AddRange(a.GetTypes());
				}
				catch (Exception e)
				{
				}
				
			}
			return RetVal.ToArray();
		}

		/// <summary>
		/// Returns all <see cref="Type"/>s in all the assemblies of the current <see cref="AppDomain"/>
		/// which match the given <see cref="TypeFilter"/>.
		/// </summary>
		/// <param name="filter">Used to filter the types.</param>
		/// <returns>The filtered List of Types</returns>
		public static Type[] GetTypes(TypeFilter filter)
		{
			Type[] types = AssemblyReflector.GetTypes();
			return AssemblyReflector.FilterTypes(types, filter);
		}

		/// <summary>
		/// Takes a <see cref="Type"/>-Array and returns all <see cref="Type"/>s of the array
		/// which match the given <see cref="TypeFilter"/>.
		/// </summary>
		/// <param name="Input"></param>
		/// <param name="filter"></param>
		/// <returns></returns>
		public static Type[] FilterTypes(Type[] Input, TypeFilter filter)
		{
			List<Type> RetVal = new List<Type>();
			foreach (Type t in Input)
			{
				if (filter.IncludeAbstract == false && t.IsAbstract == true)
					continue;
				if (filter.IncludeEnums == false && t.IsEnum == true)
					continue;
				if (filter.IncludeValueTypes == false && t.IsValueType == true)
					continue;
				if (filter.DerivedFrom != null && t.IsSubclassOf(filter.DerivedFrom) == false)
					continue;
				if (filter.Namespaces != null)
				{
					if (String.IsNullOrWhiteSpace(t.Namespace) == true)
						continue;
					if (filter.IncludeSubNamespaces == true)
					{
						foreach (String s in filter.Namespaces)
						{
							if (t.Namespace.StartsWith(s) == false)
								continue;
						}
					}
					else
					{
						foreach (String s in filter.Namespaces)
						{
							if (t.Namespace != s)
								continue;
						}
					}
				}

				RetVal.Add(t);
			}
			return RetVal.ToArray();
		}
	}
}
